/*
 *	Copyright (c) 2009 Queensland University of Technology. All rights reserved.
 *	The QUT Bioinformatics Collection is open source software released under the 
 *	Microsoft Public License (Ms-PL): http://www.microsoft.com/opensource/licenses.mspx.
 */
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Net;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace QUT.Bio.Util {
	public static class Extensions {
		
		/// <summary>
		/// Adds a formatted string to a StringBuilder.
		/// </summary>
		/// <param name="buffer"></param>
		/// <param name="format"></param>
		/// <param name="parms"></param>
		public static void Append( this StringBuilder buffer, string format, params object [] parms ) {
			buffer.Append( String.Format( format, parms ) );
		}

		public static void AddRange<T>( this ObservableCollection<T> collection, IEnumerable<T> newMembers ) {
			lock( collection ) {
				lock( newMembers ) {
					// Am I getting paranoid?
					foreach ( T x in newMembers ) {
						collection.Add( x );
					}
				}
			}
		}

		public static void InsertInOrder<T>( this ObservableCollection<T> collection, T newItem ) where T : IComparable {
			lock ( collection ) {
				int n = collection.Count;

				if ( n == 0 ) {
					collection.Add( newItem );
				}
				else if ( newItem.CompareTo( collection[0] ) < 0 ) {
					collection.Insert( 0, newItem );
				}
				else if ( newItem.CompareTo( collection[n - 1] ) >= 0 ) {
					collection.Add( newItem );
				}
				else {
					for ( int i = n - 1; i > 0; i-- ) {
						if ( newItem.CompareTo( collection[i - 1] ) >= 0 ) {
							collection.Insert( i, newItem );
							break;
						}
					}
				}
			}
		}

		public delegate int Comparison<T>( T x, T y );

		public static void InsertInOrder<T>( this ObservableCollection<T> collection, T newItem, Comparison<T> compare ) where T : IComparable {
			lock ( collection ) {
				int n = collection.Count;

				if ( n == 0 ) {
					collection.Add( newItem );
				}
				else if ( compare( newItem, collection[0] ) < 0 ) {
					collection.Insert( 0, newItem );
				}
				else if ( compare( newItem, collection[n - 1] ) >= 0 ) {
					collection.Add( newItem );
				}
				else {
					for ( int i = n - 1; i > 0; i-- ) {
						if ( compare( newItem, collection[i - 1] ) >= 0 ) {
							collection.Insert( i, newItem );
							break;
						}
					}
				}
			}
		}

		/// <summary>
		/// Inserts an item into an ObservableCollection at the appropriate position
		/// according to collation order defined by the supplied comparer.
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="collection"></param>
		/// <param name="newItem"></param>
		/// <param name="compare"></param>
		
		public static void InsertInOrder<T>( this ObservableCollection<T> collection, T newItem, IComparer<T> compare ) where T : IComparable {
			lock ( collection ) {
				int n = collection.Count;

				if ( n == 0 ) {
					collection.Add( newItem );
				}
				else if ( compare.Compare( newItem, collection[0] ) < 0 ) {
					collection.Insert( 0, newItem );
				}
				else if ( compare.Compare( newItem, collection[n - 1] ) >= 0 ) {
					collection.Add( newItem );
				}
				else {
					for ( int i = n - 1; i > 0; i-- ) {
						if ( compare.Compare( newItem, collection[i - 1] ) >= 0 ) {
							collection.Insert( i, newItem );
							break;
						}
					}
				}
			}
		}

		/// <summary>
		/// Converts each element in an enumeration into a string, then uses the
		/// separator string to glue them togehter to form a single string.
		/// </summary>
		/// <param name="objectList">A list of objects to be joined.</param>
		/// <param name="separater">A separator string that will be inserted between the items.</param>
		/// <returns>A single string containing the concatenated set of string representations.</returns>
		
		public static string Join( this IEnumerable objectList, string separater ) {
			StringBuilder b = new StringBuilder();
			bool dejaVu = false;

			lock( objectList ) {
				foreach ( object x in objectList ) {
					b.AppendFormat( "{0}{1}", ( dejaVu ? separater : "" ), x );
					dejaVu = true;
				}
			}
			
			return b.ToString();
		}
		
		public static void SetTooltip ( this UIElement element, string tooltip ) {
			element.SetValue( ToolTipService.ToolTipProperty, tooltip );
		}

		public static void SetTooltip ( this UIElement element, string format, params object [] args ) {
			element.SetValue( ToolTipService.ToolTipProperty, string.Format( format, args )  );
		}

		public static void SetColumn ( this UIElement element, int column ) {
			element.SetValue( Grid.ColumnProperty, column );
		}

		public static int GetColumn ( this UIElement element ) {
			return (int) element.GetValue( Grid.ColumnProperty );
		}

		public static void SetRow ( this UIElement element, int row ) {
			element.SetValue( Grid.RowProperty, row );
		}

		public static int GetRow ( this UIElement element ) {
			return (int) element.GetValue( Grid.RowProperty );
		}

		public static void SetColumnSpan ( this UIElement element, int columnSpan ) {
			element.SetValue( Grid.ColumnSpanProperty, columnSpan );
		}

		public static int GetColumnSpan ( this UIElement element ) {
			return (int) element.GetValue( Grid.ColumnSpanProperty );
		}

		public static void SetRowSpan ( this UIElement element, int rowSpan ) {
			element.SetValue( Grid.RowSpanProperty, rowSpan );
		}

		public static int GetRowSpan ( this UIElement element ) {
			return (int) element.GetValue( Grid.RowSpanProperty );
		}
		
		/// <summary>
		/// Appends a new row to a grid, populating it with a list of elements.
		/// <para>The new rowdefinition is returned to allow convenient adjustment by the consumer.</para>
		/// <para>The newly created row is auto height. This can be changed later if necessary.</para>
		/// </summary>
		/// <param name="grid">The grid to which the row will be added.</param>
		/// <param name="elements">A list of elements that are to be inserted into the new row. The order of these does not matter, as we assume that column and column span have been set elsewhere.</param>
		/// <returns>The newly created row.</returns>

		public static RowDefinition AddRow ( this Grid grid, params UIElement[] elements ) {
			RowDefinitionCollection rows = grid.RowDefinitions;
			int row = rows.Count;
			RowDefinition newRow = new RowDefinition{ Height = new GridLength( 1, GridUnitType.Auto ) };
			rows.Add( newRow );
			
			foreach ( UIElement element in elements ) {
				element.SetRow( row );
				grid.Children.Add( element );
			}
			
			return newRow;
		}

		public static void SetLeft ( this UIElement element, double left ) {
			element.SetValue( Canvas.LeftProperty, left );
		}

		public static void SetTop ( this UIElement element, double top ) {
			element.SetValue( Canvas.TopProperty, top );
		}

		public static double GetLeft ( this UIElement element ) {
			return (double) element.GetValue( Canvas.LeftProperty );
		}

		public static double GetTop ( this UIElement element ) {
			return (double) element.GetValue( Canvas.TopProperty );
		}
	}
}
